package de.codecrafters.tableview;

import de.codecrafters.tableview.model.TableColumnModel;
import de.codecrafters.tableview.model.TableColumnWeightModel;
import de.codecrafters.tableview.util.LogUtil;
import ohos.agp.components.*;
import ohos.agp.utils.LayoutAlignment;
import ohos.app.Context;
import ohos.global.resource.NotExistException;
import ohos.global.resource.ResourceManager;
import ohos.global.resource.WrongTypeException;

import java.io.IOException;


/**
 * The abstract implementation of an adapter used to bring data to a {@link TableHeaderView}.
 *
 * @author ISchwarz
 */
public abstract class TableHeaderAdapter extends BaseItemProvider {

    private final Context context;
    private TableColumnModel columnModel;


    /**
     * Creates a new TableHeaderAdapter.
     *
     * @param context The context that shall be used.
     */
    public TableHeaderAdapter(final Context context) {
        this(context, 0);
    }

    /**
     * Creates a new TableHeaderAdapter. (internally used)
     *
     * @param context     The context that shall be used.
     * @param columnCount The number of columns.
     */
    protected TableHeaderAdapter(final Context context, final int columnCount) {
        this(context, new TableColumnWeightModel(columnCount));
    }

    /**
     * Creates a new TableHeaderAdapter. (internally used)
     *
     * @param context     The context that shall be used.
     * @param columnModel The column model to be used.
     */
    protected TableHeaderAdapter(final Context context, final TableColumnModel columnModel) {
        super();
        this.context = context;
        this.columnModel = columnModel;
    }

    /**
     * Gives the {@link Context} of this adapter. (Hint: use this method in the {@code getHeaderView()}-method
     * to programmatically initialize new views.)
     *
     * @return The {@link Context} of this adapter.
     */
    public Context getContext() {
        return context;
    }

    /**
     * Gives the {@link ohos.agp.components.LayoutScatter} of this adapter. (Hint: use this method in the
     * {@code getHeaderView()}-method to inflate xml-layout-files.)
     *
     * @return The {@link LayoutScatter} of this adapter.
     */
    public LayoutScatter getLayoutInflater() {
        return LayoutScatter.getInstance(getContext());
    }

    /**
     * Gives the {@link ResourceManager} of this adapter. (Hint: use this method in the
     * {@code getHeaderView()}-method to resolve resources.)
     *
     * @return The {@link ResourceManager} of the context of this adapter.
     */
    public ResourceManager getResources() {
        return getContext().getResourceManager();
    }

    /**
     * Gives the {@link TableColumnWeightModel} that is currently used to render the table headers.
     *
     * @return The {@link TableColumnModel} which is currently used.
     */
    protected TableColumnModel getColumnModel() {
        return columnModel;
    }

    /**
     * Sets the {@link TableColumnModel} that will be used to render the table headers.
     *
     * @param columnModel The {@link TableColumnModel} that should be used.
     */
    protected void setColumnModel(final TableColumnModel columnModel) {
        this.columnModel = columnModel;
    }

    /**
     * Gives the column count that is currently used to render the table headers.
     *
     * @return The number of columns.
     */
    protected int getColumnCount() {
        return columnModel.getColumnCount();
    }

    /**
     * Sets the column count which is used to render the table headers.
     *
     * @param columnCount The column count that should be set.
     */
    protected void setColumnCount(final int columnCount) {
        columnModel.setColumnCount(columnCount);
    }

    @Override
    public int getCount() {
        return 1;
    }

    @Override
    public Component getComponent(int i, Component component, ComponentContainer componentContainer) {
        final DirectionalLayout rowView = new DirectionalLayout(getContext());
        rowView.setOrientation(Component.HORIZONTAL);
        final ComponentContainer.LayoutConfig rowLayoutParams = new ComponentContainer.LayoutConfig(ComponentContainer.LayoutConfig.MATCH_PARENT, ComponentContainer.LayoutConfig.MATCH_CONTENT);
        rowView.setLayoutConfig(rowLayoutParams);
        rowView.setAlignment(LayoutAlignment.VERTICAL_CENTER);

        final int tableWidth = componentContainer.getWidth();
        for (int columnIndex = 0; columnIndex < getColumnModel().getColumnCount(); columnIndex++) {
            Component cellView = null;
            try {
                cellView = getHeaderView(columnIndex, rowView);
            } catch (NotExistException e) {
                LogUtil.error(e.getMessage());
            } catch (WrongTypeException e) {
                LogUtil.error(e.getMessage());
            } catch (IOException e) {
                LogUtil.error(e.getMessage());
            }
            if (cellView == null) {
                cellView = new Text(getContext());
            }

            final int cellWidth = getColumnModel().getColumnWidth(columnIndex, tableWidth);
            final ComponentContainer.LayoutConfig cellLayoutParams = new ComponentContainer.LayoutConfig(cellWidth, ComponentContainer.LayoutConfig.MATCH_CONTENT);
            cellView.setLayoutConfig(cellLayoutParams);
            rowView.addComponent(cellView);
        }

        return rowView;
    }

    /**
     * Method that gives the header views for the different columns.
     *
     * @param columnIndex The index of the column to return the header view.
     * @param parentView  The view to which the returned view will be added.
     * @return The created header view for the given column.
     * @throws IOException
     * @throws WrongTypeException
     * @throws NotExistException
     */
    public abstract Component getHeaderView(int columnIndex, ComponentContainer parentView) throws NotExistException, WrongTypeException, IOException;

}
